#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <memory>
#include <vector>
#include <functional>
using namespace std;

template<class T>
class SmartPtr {
public:
	SmartPtr(T* ptr = nullptr)
		: _ptr(ptr)
	{}
	~SmartPtr()
	{
		if (_ptr)
			delete _ptr;
	}
	T& operator*() { return *_ptr; }
	T* operator->() { return _ptr; }
private:
	T* _ptr;
};

struct Date
{
	int _year;
	int _month;
	int _day;

	Date (int year = 1, int month = 1, int day = 1)
		: _year(year)
		, _month(month)
		, _day(day)
	{}

	~Date() 
	{
		cout << "~Date()" << endl;
	}

};

class Test
{
public:
	Test() : _num(0)
	{
		cout << "Test() 构造成功..." << endl;
	}
	Test(int x) : _num(0)
	{
		cout << "Test(int x) 构造成功, x = " << x << endl;
	}
	Test(string str) : _num(0)
	{
		cout << "Test(string str) 构造成功, str = " << str << endl;
	}
	~Test()
	{
		cout << "~Test() 析构成功..." << endl;
	}
	void setValue(int v)
	{
		this->_num = v;
	}
	void print()
	{
		cout << "_num: " << this->_num << endl;
	}
private:
	int _num;
};

template<class T>
class DeleteArray {
public:
	void operator()(T* ptr) {
		delete[] ptr;
	}
};

class Fclose {
public:
	void operator()(FILE* ptr) {
		cout << "fclose:" << ptr << endl;
		fclose(ptr);
	}
};
//int main(){
//	////智能指针可以自动释放
//	//SmartPtr<Date> sp1(new Date);// new出来之后就不用给普通指针，直接交给智能指针
//	////但是其拷贝很麻烦，因为C++对于内置类型生成的拷贝是浅拷贝，导致sp2和sp1的指针就是一样的了
//	
//	//auto_ptr可以实现拷贝
//	SmartPtr<int> ap1(new int(1));
//	
//	//auto_ptr拷贝时，管理权限转移，被拷贝悬空
//	SmartPtr<int> ap2(ap1); //拷贝构造
//
//	SmartPtr<int> ap3(new int(2));
//	SmartPtr<int> ap4(new int(2));
//	ap4 = ap3; // 拷贝赋值
//
//	//但是这样会使程序会崩
//	//因为auto_ptr的拷贝是管理权转移，这样就会导致ap1空了
//
//	return 0;
//}


////———————— auto_ptr使用 ————————
//int main(){
//	////智能指针可以自动释放
//	//SmartPtr<Date> sp1(new Date);// new出来之后就不用给普通指针，直接交给智能指针
//	////但是其拷贝很麻烦，因为C++对于内置类型生成的拷贝是浅拷贝，导致sp2和sp1的指针就是一样的了
//	
//	auto_ptr<Date> ap1(new Date);
//	//拷贝时，管理权限转移，被拷贝悬空
//	auto_ptr<Date> ap2(ap1);
//	//下面这样会使程序会崩，因为auto_ptr的拷贝是管理权转移，这样就会导致ap1空了
//	ap1->_year++;
//
//	return 0;
//}


////——————  unique_ptr 使用 ——————————
//
//int main() {
//	unique_ptr<Date> up1(new Date);
//	//不支持拷贝
//	//unique_ptr<Date> up2(up1);
//	
//	//unique_ptr<Date> up2(new Date[6]); //error，因为类型不匹配，由于我们是用new []构造的，那么就要用delete[]去销毁
//	//定制删除器解决上述问题
//	unique_ptr<Date, DeleteArray<Date>> up2(new Date[6]); //用定制的删除器
//	//unique_ptr<Date[]> up2(new Date[5]);
//	unique_ptr<FILE, Fclose> up3(fopen("test.cpp", "r"));
//
//	return 0;
//}



//int main()
//{
//	/*--------------------------  一，初始化智能指针unique_ptr  ------------------------------*/
//	// 1.通过构造函数初始化
//	unique_ptr<int> up1(new int(3));
//
//	//unique_ptr<int> up = up1;  // 编译错误，不能复制
//
//	// 2.通过移动函数初始化
//	unique_ptr<int> up2 = move(up1); // 现在up2独占资源，up1变为空
//
//	// 3.通过reset,释放资源并将指针置为空，然后再初始化
//	up1.reset(new int(7));
//	
//	//对比reset，release会释放资源的所有权但不删除，返回原始指针
//	up1.release();
//
//	/*--------------------------  二，unique_ptr的使用  ------------------------------*/
//	//1.方法一
//	unique_ptr<Test> up3(new Test(666));
//	Test* pt = up3.get();
//	pt->setValue(6);
//	pt->print();
//
//	//2.方法二
//	up3->setValue(777);
//	up3->print();
//
//	/*------------------------------------  三，指定删除器  -----------------------------------*/
//	////1.函数指针类型
//	//using ptrFunc = void(*)(Test*);
//	//unique_ptr<Test, ptrFunc> up4(new Test("hello"), [](Test* t) {
//	//    cout << "-----------------------" << endl;
//	//    delete t;
//	//    });
//
//	//2.仿函数类型（利用可调用对象包装器）
//	unique_ptr<Test, function<void(Test*)>> up4(new Test("hello"), [](Test* t) {
//		cout << "-----------------------" << endl;
//		delete t;
//		});
//
//	/*---------- 四，独占(共享)的智能指针可以管理数组类型的地址，能够自动释放 ---------*/
//	unique_ptr<Test[]> up5(new Test[3]);
//
//	//在c++11中shared_ptr不支持下面的写法，c++11以后才支持的
//	shared_ptr<Test[]> up6(new Test[3]);
//
//	return 0;
//}




// //—————————— shared_ptr 使用————————
//int main() {
//	//vector<shared_ptr<Date>> v;
//	shared_ptr<Date> sp1(new Date);
//	shared_ptr<Date> sp2(sp1);
//	shared_ptr<Date> sp3(sp2);
//
//	cout << sp1.use_count() << endl; //查看其引用计数
//	
//	//定制删除器
//	shared_ptr <Date[]> sp4(new Date[5]);
//	//shared_ptr<FILE, Fclose> up5(fopen("test.cpp", "r")); //不支持传这个模板参数
//	shared_ptr<FILE> up5(fopen("test.cpp", "r"), Fclose());
//
//	shared_ptr<Date> sp6 = make_shared<Date>(2024, 8, 5);
//	shared_ptr<int> sp7((int*)malloc(40), [](int* ptr)
//		{
//			cout << "free：" << ptr << endl;
//			free(ptr);
//		});
//
//	return 0;
//}


//int main()
//{
//	/*----------------------------  一，初始化智能指针shared_ptr  ------------------------------*/
//	// 1.通过构造函数初始化
//	shared_ptr<int> sp1(new int(3));
//	cout << "sp1管理的内存引用计数：" << sp1.use_count() << endl;
//
//	// 2.通过移动和拷贝构造函数初始化
//	shared_ptr<int> sp2 = move(sp1);
//	cout << "sp1管理的内存引用计数：" << sp1.use_count() << endl;
//	cout << "sp2管理的内存引用计数：" << sp2.use_count() << endl;
//
//	shared_ptr<int> sp3 = sp2; //赋值
//	cout << "sp2管理的内存引用计数: " << sp2.use_count() << endl;
//	cout << "sp3管理的内存引用计数: " << sp3.use_count() << endl;
//
//	// 3.通过 std::make_shared初始化
//	shared_ptr<int> sp4 = make_shared<int>(8);
//	shared_ptr<Test> sp5 = make_shared<Test>(7);
//	shared_ptr<Test> sp6 = make_shared<Test>("Love Life");
//
//	// 4.通过reset初始化
//	sp6.reset();//重置sp6, ps6的引用基数为0
//	cout << "sp6管理的内存引用计数: " << sp6.use_count() << endl;
//
//	sp5.reset(new Test("hello")); //重置了指针的指向对象，原来的对象已经释放
//	cout << "sp5管理的内存引用计数: " << sp5.use_count() << endl;
//
//	cout << endl << endl;
//
//	/*-----------------------------  二，共享智能指针shared_ptr的使用  ------------------------------*/
//	// 1.方法一
//	Test* t = sp5.get();
//	t->setValue(1000);
//	t->print();
//
//	// 2.方法二
//	sp5->setValue(7777);
//	sp5->print();
//
//	cout << endl << endl;
//
//	///*------------------------------  三，指定删除器  -----------------------------------*/
//	 // 1.简单举例
//	shared_ptr<Test> ppp(new Test(100), [](Test* t) {
//		//释放内存
//		cout << "Test对象的内存被释放了......." << endl;
//		delete t;
//		});
//	printf("----------------------------------------------------------------------\n");
//	//cout << "ppp管理的内存引用计数: " << ppp.use_count() << endl;
//
//	//// 2.如果是数组类型的地址，就需要自己写指定删除器，否则内存无法全部释放
//	//	//shared_ptr<Test> p1(new Test[5], [](Test* t) {
//	//	//    delete[]t;
//	//	//    });
//
//	////3.也可以使用c++给我们提供的 默认删除器函数（函数模板）
//	shared_ptr<Test> p2(new Test[3], default_delete<Test[]>());
//	//cout << "p2管理的内存引用计数: " << sp6.use_count() << endl;
//
//
//	////4.c++11以后可以这样写 也可以自动释放内存
//	shared_ptr<Test[]> p3(new Test[3]);
//	//cout << "p3管理的内存引用计数: " << sp6.use_count() << endl;
//
//
//	return 0;
//}

////此外，我们还可以自己封装一个函数模板make_shared_array方法来让shared_ptr支持数组，代码如下:
////有了这个函数模板，我们就不用自己去释放数组类型的地址了
//template <typename T>
//shared_ptr<T> make_share_array(size_t size)
//{
//	//返回匿名对象
//	return shared_ptr<T>(new T[size], default_delete<T[]>());
//}
//
//int main()
//{
//	shared_ptr<int> ptr1 = make_share_array<int>(10);
//	cout << ptr1.use_count() << endl;
//
//	shared_ptr<string> ptr2 = make_share_array<string>(7);
//	cout << ptr2.use_count() << endl;
//}


int main()
{
	shared_ptr<int> sp1(new int[5], [](int* ptr)
		{
			cout << "delete[]:" << ptr << endl;
			delete[] ptr;
		});

	shared_ptr<int> sp2((int*)malloc(40), [](int* ptr)
		{
			cout << "free：" << ptr << endl;
			free(ptr);
		});

	shared_ptr<FILE> sp3(fopen("test.cpp", "r"), [](FILE* ptr)
		{
			cout << "fclose: " << ptr << endl;
			fclose(ptr);
		});

	return 0;
}







//// ———————— weadk_ptr ——————————
//int main()
//{
//	// weak_ptr不支持管理资源，不支持RAII
//	//std::weak_ptr<Date> wp1(new Date);
//
//	weak_ptr<Date> wp;
//	shared_ptr<Date> sp; //保证不过期
//	{
//		shared_ptr<Date> n1(new Date);
//		wp = n1;
//		cout << wp.expired() << endl;
//		n1->_day++;
//		//sp = wp.lock();
//
//	}
//	// 出了作用域就失效了
//	cout << wp.expired() << endl;
//
//}


//int main()
//{
//	/*----------------------------  一，初始化智能指针weak_ptr  ------------------------------*/
//	shared_ptr<int> sp(new int(2));
//
//	weak_ptr<int> wp1;; //构造了一个空weak_ptr对象
//	weak_ptr<int> wp2(wp1); //通过一个空weak_ptr对象构造了另一个空weak_ptr对象
//	weak_ptr<int> wp3(sp); //通过一个shared_ptr对象构造了一个可用的weak_ptr实例对象
//
//	weak_ptr<int> wp4; 
//	wp4 = sp; //通过一个shared_ptr对象构造了一个可用的weak_ptr实例对象（这是一个隐式类型转换）
//
//	weak_ptr<int> wp5;
//	wp5 = wp3; //通过一个weak_ptr对象构造了一个可用的weak_ptr实例对象
//
//	/*----------------------------  二，weak_ptr常用函数  ------------------------------*/
//	
//	// 1.通过调用weak_ptr类提供的use_count()方法可以获得当前共享该资源的shared_ptr数量
//	cout << "wp1管理的shared_ptr内存引用计数：" << wp1.use_count() << endl;
//	cout << "wp2管理的shared_ptr内存引用计数：" << wp2.use_count() << endl;
//	cout << "wp3管理的shared_ptr内存引用计数：" << wp3.use_count() << endl;
//
//	cout << "wp4管理的shared_ptr内存引用计数：" << wp4.use_count() << endl;
//	cout << "wp5管理的shared_ptr内存引用计数：" << wp5.use_count() << endl;
//
//	cout << endl << endl;
//
//	// 2.通过调用std::weak_ptr类提供的expired()方法来判断
//	//判断指针所指的内存空间是否被释放掉 / 指针是否为空 / 是否还有shared_ptr指针指向weak_ptr指向的内存空间
//	shared_ptr<int> sp2 = make_shared<int>(10);
//	weak_ptr<int> wp6(sp2); // shared_ptr初始化weak_ptr  
//	sp2.reset(new int); // 此时，已没有一个shared_ptr指针指向weak_ptr指向的内存区域  
//	cout << "是否已没有shared_ptr指针指向该内存区域：" << wp6.expired() << endl;
//	shared_ptr<int> sp22 = nullptr;
//	weak_ptr<int> wp7(sp22);
//	cout << "weak_ptr指针是否为空：" << wp7.expired() << endl;
//
//	// 3.通过调用weak_ptr类提供的lock()方法来获取管理所监测资源的shared_ptr对象,返回一个shared_ptr，增加引用计数
//	shared_ptr<int> sp3 = wp3.lock(); // 利用返回的shared_ptr初始化  
//	cout << "share_ptr的初始化为：" <<*sp3 << endl;
//	cout << "wp3管理的shared_ptr内存引用计数：" << wp3.use_count() << endl;
//
//	return 0;
//}


////  ———————————— 循环引用的解决 ——————————
//struct ListNode{
//	int _data;
//	/*shared_ptr<ListNode> _next;
//	shared_ptr<ListNode> _prev;*/
//
//	//用weak_ptr就可以避免内存泄露
//	weak_ptr<ListNode> _next;
//	weak_ptr<ListNode> _prev;
//	~ListNode()
//	{
//		cout << "~ListNode()" << endl;
//	}
//};
//
//
//int main()
//{
//	// 下面这就是循环引用 --> 内存泄露
//	std::shared_ptr<ListNode> n1(new ListNode);
//	std::shared_ptr<ListNode> n2(new ListNode);
//
//	n1->_next = n2;
//	n2->_prev = n1; //互相指向，就会出现内存泄露
//
//	cout << n1.use_count() << endl;
//	cout << n2.use_count() << endl;
//
//	return 0;
//}







//int main()
//{
//	//使用自定义的fclose模板
//	std::unique_ptr<FILE, Fclose> up(fopen("test.txt", "r"));
//	std::shared_ptr<FILE> sp(fopen("test.txt", "r"), Fclose());
//
//	// 创建一个shared_ptr，管理一个打开的文件
//	// 使用fclose作为定制删除器
//	std::shared_ptr<FILE> sp(fopen("test.txt", "w"), fclose);
//	//std::unique_ptr<FILE> up(fopen("test.txt", "w"), fclose);
//	// 写入一些内容到文件
//	fputs("Hello world", sp.get());
//
//
//	// 当file离开作用域时，会调用fclose来关闭文件
//}
//
